package com.jial08.mybatisgenerator.plusgenerator;

import java.util.ArrayList;
import java.util.List;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import org.apache.commons.lang3.StringUtils;

/**
 * <p>功能描述：mybatis plus 代码生成器。</p>
 * <p>jl</p>
 *
 * @since JDK1.8
 * <p>创建日期：2019-08-14 11:53。</p>
 * <p>更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。</p>
 * 详细参考：https://mp.baomidou.com/guide/generator.html
 */
public class MybatisPlusGenerator {
	/**
	 * 模版引擎配置
	 */
	private static AbstractTemplateEngine templateEngine = new FreemarkerTemplateEngine();  // 默认模版引擎是 velocity，这里选择 freemarker
	/**
	 * 数据源配置 FIXME
	 */
	private static DbType dbType = DbType.MYSQL;    // 数据库类型
	private static String url = "";    // 驱动连接的URL
	private static String driverName = "com.mysql.jdbc.Driver";    // 驱动名称
	private static String username = "";    // 数据库连接用户名
	private static String password = "";    // 数据库连接密码
	/**
	 * 数据库表配置
	 */
	// FIXME
	private static String superEntityClass = "cn.fancylab.model.BaseObject";    // 自定义继承的Entity类全称，带包名
	private static String superEntityColumns = "";    // 自定义基础的Entity类，公共字段，多个用英文,隔开
	private static String superMapperClass = "";    // 自定义继承的Mapper类全称，带包名
	private static String superServiceClass = "";    // 自定义继承的Service类全称，带包名
	private static String superServiceImplClass = "";    // 自定义继承的ServiceImpl类全称，带包名
	private static String superControllerClass = "";    // 自定义继承的Controller类全称，带包名
	// FIXME
	private static String include = "";    // 需要包含的表名，允许正则表达式（与exclude二选一配置），多表用英文,隔开
	private static boolean entityLombokModel = false;   // 【实体】是否为lombok模型（默认 false）
	private static boolean restControllerStyle = false;   // 生成 @RestController 控制器
	private static boolean controllerMappingHyphenStyle = true;   // 驼峰转连字符
	/**
	 * 包名配置 FIXME
	 */
	private static String parentPackage = "com.llwh.mall";  // 父包名。如果为空，将下面子包名必须写全部， 否则就只需写子包名
	private static String moduleNamePackage = "";  // 父包模块名，此值如果不为空，则除 xml 外的代码都将在该包下生成
	/**
	 * 模块名，生成的类都在该模块下 FIXME
	 */
	private static String commonPackage = "";  // 各模块儿公共模块名，如 entity、service 模块下的代码会在该包下
	private static String entityPackage = "model" + (StringUtils.isNotBlank(commonPackage) ? StringPool.DOT + commonPackage : commonPackage);  // Entity包名
	private static String servicePackage = "service" + (StringUtils.isNotBlank(commonPackage) ? StringPool.DOT + commonPackage : commonPackage);  // Service包名
	private static String serviceImplPackage = "service" + (StringUtils.isNotBlank(commonPackage) ? StringPool.DOT + commonPackage : commonPackage) + ".impl";  // Service Impl包名
	private static String mapperPackage = "mapper" + (StringUtils.isNotBlank(commonPackage) ? StringPool.DOT + commonPackage : commonPackage);  // Mapper包名
	/**
	 * Mapper XML包名 FIXME
	 */
	private static String xmlPackage = "/resources/mapper";
	//	private static String controllerPackage = "web.action.admin";  // Controller包名
	private static String controllerPackage = null;  // Controller包名
	/**
	 * 模版配置
	 * 设置为空或 null 将不生成该模块儿代码，不设置则用默认配置生成，这里为了区分，不生成模块儿的代码统一用 null
	 * 注意不要带上.ftl(freemarker)或者是.vm(velocity), 会根据使用的模板引擎自动识别，xmlTemplate 带是因为重新自定义了 xml 的输出路径，需要以文件识别
	 */
	private static String entityTemplate = "/mybatisplus/templates/entity.java";  // Java 实体类模板，例如 /mybatisplus/templates/entity.java.ftl
	private static String serviceTemplate = "/mybatisplus/templates/service.java";  // Service 类模板
	private static String serviceImplTemplate = "/mybatisplus/templates/serviceImpl.java";  // Service impl 实现类模板
	private static String mapperTemplate = "/mybatisplus/templates/mapper.java";  // mapper 模板
	private static String xmlTemplate = "/mybatisplus/templates/mapper.xml.ftl";  // mapper xml 模板
//	private static String controllerTemplate = "/mybatisplus/templates/controller.java";  // controller 控制器模板
	private static String controllerTemplate = null;  // controller 控制器模板
	/**
	 * 全局策略 FIXME
	 */
	private static String outputDir = "/Users/jl/IdeaProjects/mall/mall-mbg";   // 代码输出路径，绝对路径
	private static boolean fileOverride = true;   // 是否覆盖已有文件
	private static boolean open = false;   // 是否打开输出目录
	// FIXME
	private static String author = "jl";  // 开发人员，该值必须有，否则报错
	private static boolean activeRecord = false;  // 开启 ActiveRecord 模式
	private static boolean baseResultMap = true;  // 开启 BaseResultMap
	private static boolean baseColumnList = true;  // 开启 baseColumnList
	// FIXME
	private static DateType dateType = DateType.ONLY_DATE;  // 时间类型对应策略
	// 如下配置 %s 为占位符
	private static String entityName = "";   // 实体命名方式，%sEntity 生成 UserEntity
	private static String mapperName = "%sMapper";   // mapper 命名方式
	private static String xmlName = "%sMapper";   // Mapper xml 命名方式
	private static String serviceName = "Mbg%sService";   // service 命名方式
	private static String serviceImplName = "Mbg%sServiceImpl";   // service impl 命名方式
	private static String controllerName = "%sController";   // controller 命名方式
	/**
	 * 自定义模版
	 */
	private static boolean untrans = false;  // 创建 untrans 模块自定义模版
	private static String untransServicePackage = "untrans" + (StringUtils.isNotBlank(commonPackage) ? StringPool.DOT + commonPackage : commonPackage);  // Untrans Service 包名
	private static String untransServiceImplPackage = "untrans" + (StringUtils.isNotBlank(commonPackage) ? StringPool.DOT + commonPackage : commonPackage) + ".impl";  // Untrans Service Impl包名
	private static String untransServiceTemplate = "/mybatisplus/templates/untransService.java.ftl";  // untransService 类模板
	private static String untransServiceImplTemplate = "/mybatisplus/templates/untransServiceImpl.java.ftl";  // untransServiceImpl 类模板
	private static String untransServiceName = "UntransService";   // Untrans Service 命名方式
	private static String untransServiceImplName = "UntransServiceImpl";   // Untrans Service impl 命名方式

	public static void main(String[] args) {
		/*
		 * 代码生成器
		 */
		AutoGenerator mpg = new AutoGenerator();
		if (templateEngine != null) {
			mpg.setTemplateEngine(templateEngine);
		}
		/*
		 * 全局配置
		 */
		GlobalConfig gc = new GlobalConfig();
		gc.setOutputDir(outputDir + "/src/main/java");
		gc.setFileOverride(fileOverride);
		gc.setOpen(open);
		gc.setAuthor(author);
		gc.setActiveRecord(activeRecord);
		gc.setBaseResultMap(baseResultMap);
		gc.setBaseColumnList(baseColumnList);
		gc.setDateType(dateType);
		if (StringUtils.isNotBlank(entityName)) {
			gc.setEntityName(entityName);
		}
		if (StringUtils.isNotBlank(mapperName)) {
			gc.setMapperName(mapperName);
		}
		if (StringUtils.isNotBlank(xmlName)) {
			gc.setXmlName(xmlName);
		}
		if (StringUtils.isNotBlank(serviceName)) {
			gc.setServiceName(serviceName);
		}
		if (StringUtils.isNotBlank(serviceImplName)) {
			gc.setServiceImplName(serviceImplName);
		}
		if (StringUtils.isNotBlank(controllerName)) {
			gc.setControllerName(controllerName);
		}
		mpg.setGlobalConfig(gc);
		/*
		 * 数据源配置
		 */
		DataSourceConfig dsc = new DataSourceConfig();
		dsc.setDbType(dbType);
		dsc.setUrl(url);
		dsc.setDriverName(driverName);
		dsc.setUsername(username);
		dsc.setPassword(password);
		//类型转换
		dsc.setTypeConvert((globalConfig, fieldType) -> {
			String t = fieldType.toLowerCase();
			if (t.contains("datetime")) {
				return DbColumnType.TIMESTAMP;
			}
			//其它字段采用默认转换（非mysql数据库可以使用其它默认的数据库转换器）
			return new MySqlTypeConvert().processTypeConvert(globalConfig, fieldType);
		});
		mpg.setDataSource(dsc);
		/*
		 * 数据库表配置
		 */
		StrategyConfig strategy = new StrategyConfig();
		strategy.setNaming(NamingStrategy.underline_to_camel);  // 下划线转驼峰命名
		strategy.setColumnNaming(NamingStrategy.underline_to_camel);    // 数据库表字段映射到实体的命名策略, 未指定按照 naming 执行
		if (StringUtils.isNotBlank(superEntityClass)) {
			strategy.setSuperEntityClass(superEntityClass);
		}
		if (StringUtils.isNotBlank(superEntityColumns)) {
			strategy.setSuperEntityColumns(superEntityColumns.split(","));
		}
		if (StringUtils.isNotBlank(superMapperClass)) {
			strategy.setSuperMapperClass(superMapperClass);
		}
		if (StringUtils.isNotBlank(superServiceClass)) {
			strategy.setSuperServiceClass(superServiceClass);
		}
		if (StringUtils.isNotBlank(superServiceImplClass)) {
			strategy.setSuperServiceImplClass(superServiceImplClass);
		}
		if (StringUtils.isNotBlank(superControllerClass)) {
			strategy.setSuperControllerClass(superControllerClass);
		}
		strategy.setInclude(include.split(","));
		strategy.setEntityLombokModel(entityLombokModel);
		strategy.setRestControllerStyle(restControllerStyle);
		strategy.setControllerMappingHyphenStyle(controllerMappingHyphenStyle);
		mpg.setStrategy(strategy);
		/*
		 * 包名配置
		 */
		PackageConfig pc = new PackageConfig();
		pc.setParent(parentPackage);
		if (StringUtils.isNotBlank(moduleNamePackage)) {
			pc.setModuleName(moduleNamePackage);
		}
		pc.setEntity(entityPackage);
		pc.setMapper(mapperPackage);
		if (StringUtils.isNotBlank(servicePackage)) {
			pc.setService(servicePackage);
		}
		if (StringUtils.isNotBlank(serviceImplPackage)) {
			pc.setServiceImpl(serviceImplPackage);
		}
		if (StringUtils.isNotBlank(controllerPackage)) {
			pc.setController(controllerPackage);
		}
		pc.setXml(xmlPackage);
		mpg.setPackageInfo(pc);
		/*
		 * 模版配置
		 */
		TemplateConfig tc = new TemplateConfig();
		if (entityTemplate == null || StringUtils.isNotBlank(entityTemplate)) {
			tc.setEntity(entityTemplate);
		}
		if (serviceTemplate == null || StringUtils.isNotBlank(serviceTemplate)) {
			tc.setService(serviceTemplate);
		}
		if (serviceImplTemplate == null || StringUtils.isNotBlank(serviceImplTemplate)) {
			tc.setServiceImpl(serviceImplTemplate);
		}
		if (mapperTemplate == null || StringUtils.isNotBlank(mapperTemplate)) {
			tc.setMapper(mapperTemplate);
		}
		tc.setXml(null);
		if (controllerTemplate == null || StringUtils.isNotBlank(controllerTemplate)) {
			tc.setController(controllerTemplate);
		}
		mpg.setTemplate(tc);
		/*
		 * 注入 injectionConfig 配置
		 * 注意：该配置必须有，否则会报空指针异常
		 */
		InjectionConfig cfg = new InjectionConfig() {
			@Override
			public void initMap() {
				// to do nothing
			}
		};
		// 自定义输出配置
		List<FileOutConfig> focList = new ArrayList<>();
		// 自定义 xml 输出配置
		if (StringUtils.isNotBlank(xmlTemplate)) {
			focList.add(new FileOutConfig(xmlTemplate) {
				@Override
				public String outputFile(TableInfo tableInfo) {
					// 自定义 xml 输出文件名
					return outputDir + "/src/main" + xmlPackage + StringPool.SLASH + tableInfo.getXmlName() + StringPool.DOT_XML;
				}
			});
		}
		// 自定义 untrans 输出模版
		if (untrans) {
			// 自定义 untrans Service 输出模版
			focList.add(new FileOutConfig(untransServiceTemplate) {
				@Override
				public String outputFile(TableInfo tableInfo) {
					// 自定义 xml 输出文件名
					return outputDir + "/src/main/java/" + parentPackage.replace(StringPool.DOT, StringPool.SLASH) + StringPool.SLASH + untransServicePackage.replace(StringPool.DOT, StringPool.SLASH) + StringPool.SLASH + tableInfo.getEntityName() + untransServiceName + StringPool.DOT_JAVA;
				}
			});
			// 自定义 untrans ServiceImpl 输出模版
			focList.add(new FileOutConfig(untransServiceImplTemplate) {
				@Override
				public String outputFile(TableInfo tableInfo) {
					// 自定义 xml 输出文件名
					return outputDir + "/src/main/java/" + parentPackage.replace(StringPool.DOT, StringPool.SLASH) + StringPool.SLASH + untransServiceImplPackage.replace(StringPool.DOT, StringPool.SLASH) + StringPool.SLASH + tableInfo.getEntityName() + untransServiceImplName + StringPool.DOT_JAVA;
				}
			});
		}
		cfg.setFileOutConfigList(focList);
		mpg.setCfg(cfg);

		mpg.execute();
		System.out.println("代码生成完毕");
	}

}
